/******************************************************************
 * Copyright @ 2023 广州牛师帮科技文化有限公司. All rights reserverd.
 * @file   src\component\RouteGuard.tsx
 * @author 朱剑豪
 * @date   2023/03/28 17:49
 * @desc   守卫路由
 ******************************************************************/
import { handleLoginInfo, useLoginInfo } from '@/hooks/useLoginInfo';
import { LoginInfo, SSO } from '@nsb/user-center-sso-plugin';
import React, { Suspense, useEffect } from 'react';
import { Navigate, Route as _Route, useLocation } from 'react-router';
import { Paths } from '../paths';
import { Default } from './SuspenseFallback/Default';
import ErrorBoundary from 'antd/es/alert/ErrorBoundary';

export namespace RouteGuard {

  export interface ComponentProps {
    path: Paths.All;
    children: React.ReactElement;
  }

  export let _sso: SSO | undefined;

  export function Component(props: ComponentProps) {
    const permission = Paths.Permissions[props.path];
    const hasToken = !!useLoginInfo('token') || permission === undefined;
    const hasPermission = Paths.usePermission()(props.path);

    const { pathname, search, hash } = useLocation();
    const navigate = Paths.useNavigate();

    useEffect(() => {
      if (hasToken) { return; }
      const sso = _sso || new SSO({
        path: "/sso_view",
        origin: __USER_CENTER_SSO_ORIGIN__,
        domainId: __SSO_DOMAIN_ID__,
        device: "goltach_windows",
      })
      const onFail = (any: any) => {
        console.log('[SSO] onFail:', any)
        // navigate(Paths.All.Login, { replace: true, state: pathname + search + hash })
      }
      const onOk = (info: LoginInfo) => {
        console.log('[SSO] onOk:', info)
        handleLoginInfo(info);
      };
      sso.on("error", onFail);
      sso.on('reject', onFail);
      sso.on('resolve', onOk);

      if (!_sso) {
        _sso = sso;
        sso.on("error", () => delete RouteGuard._sso);
        sso.on('reject', () => delete RouteGuard._sso);
        sso.on('resolve', () => delete RouteGuard._sso);
      }
      return () => {
        sso.off("error", onFail);
        sso.off('reject', onFail);
        sso.off('resolve', onOk);
      }

    }, [pathname, search, hasToken, navigate, hash]);

    if (!hasToken) {
      return null;
    } else if (!hasPermission) {
      console.info('need permission. require:', permission)
      return <Navigate to={Paths.All.Main} replace />
    } else {
      return <ErrorBoundary>{props.children}</ErrorBoundary>;
    }
  }

  export function Route(path: Paths.All): React.ReactNode {
    const Component = Paths.Routes[path];
    if (!Component) {
      console.error(`${path} 未找到对应的页面，检查Paths.Routes中是否指定了正确的页面`)
      return null;
    }

    const loading = Paths.Loadings[path] || <Default />;
    const children = Paths.Relations[path]?.map(Route);
    const element = (
      <RouteGuard.Component path={path}>
        <Suspense fallback={loading}>
          <Component />
        </Suspense>
      </RouteGuard.Component>
    )
    return (
      <_Route key={path} path={path} element={element} >
        {children}
      </_Route>
    )
  }
}
